package com.dein.broadcast.service.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import java.util.Properties;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericItemBasedRecommender;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.JDBCDataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.ItemBasedRecommender;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.ItemSimilarity;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.dein.broadcast.dao.BroadcastDao;
import com.dein.broadcast.model.Broadcast;
import com.dein.broadcast.service.BroadcastService;
import com.dein.music.model.Music;
import com.mysql.jdbc.jdbc2.optional.MysqlDataSource;

@Service
public class BroadcastServiceImpl implements BroadcastService {

	@Autowired
	private BroadcastDao broadcastDao;

	private static final int HOWMANY = 5;
	private static final int NEARESTN = 2;

	@Override
	public boolean broadcastExist(String broadcastName) {
		String result = broadcastDao.broadcastExist(broadcastName);
		if (result == null) {
			return false;
		}
		return true;
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public boolean createBroadcast(String broadcastName, long[] musicIds)
			throws Exception {
		try {
			Broadcast broadcast = new Broadcast();
			broadcast.setBroadcastName(broadcastName);
			broadcastDao.addBroadcast(broadcast);
			broadcastDao.addBroadcastMusicList(broadcast.getBroadcastId(),
					musicIds);
		} catch (Exception e) {
			throw e;
		}
		return true;
	}

	@Override
	public List<Broadcast> getBroadcastList() {
		return broadcastDao.getBroadcastList();
	}

	@Override
	public List<Music> getBroadcastMusicList(int broadcastId) {
		return broadcastDao.getBroadcastMusicList(broadcastId);
	}

	@Override
	public boolean updateBroadcast(int broadcastId, String broadcastName) {
		try {
			broadcastDao.updateBroadcast(broadcastId, broadcastName);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	@Override
	public boolean deleteBroadcastMusic(int broadcastId, long musicId) {
		try {
			broadcastDao.deleteBroadcastMusic(broadcastId, musicId);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	@Override
	public boolean addBroadcastMusic(int broadcastId, long musicId) {
		try {
			broadcastDao.addBroadcastMusic(broadcastId, musicId);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	@Override
	public boolean deleteBroadcast(int broadcastId) {
		try {
			broadcastDao.deleteBroadcast(broadcastId);
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	@Override
	public List<Music> playPublicBroadcast(int broadcastId) {
		int number = broadcastDao.numberOfSongsOnPublicBroadcast(broadcastId);
		if(number<HOWMANY){
			return broadcastDao.playPublicBroadcast(broadcastId, 0, number);
		}else {
			int begin = (int) Math.floor(Math.random() * (number - HOWMANY + 1));
			return broadcastDao.playPublicBroadcast(broadcastId, begin, HOWMANY);
		}
	}

	@Override
	public List<Music> playRedHeartBroadcast(long userId) {
		int number = broadcastDao.numberOfSongsOnRedHeartBroadcast(userId);
		System.out.println(number);
		if(number<HOWMANY){
			return broadcastDao.playRedHeartBroadcast(userId, 0, number);
		}else {
			int begin = (int) Math.floor(Math.random() * (number - HOWMANY + 1));
			return broadcastDao.playRedHeartBroadcast(userId, begin, HOWMANY);
		}
	}

	@Override
	public List<Music> playPrivateBroadcast(long userId) {
		return null;
	}

	public JDBCDataModel getMusicPreferenceDataModel() throws Exception {
		Properties properties = new Properties();
		File file = new File("src/com/dein/resource/jdbc.properties");
		properties.load(new FileInputStream(file.getAbsolutePath()));

		MysqlDataSource dataSource = new MysqlDataSource();
		dataSource.setUrl(properties.getProperty("jdbc.url"));
		dataSource.setUser(properties.getProperty("jdbc.username"));
		dataSource.setPassword(properties.getProperty("jdbc.password"));

		JDBCDataModel dataModel = new MySQLJDBCDataModel(dataSource,
				"music_preference", "userId", "musicId", "preference", null);
		return dataModel;
	}

	public List<RecommendedItem> itemBasedCF(DataModel dataModel, long userId,
			int howMany) throws TasteException {
		ItemSimilarity similarity = new PearsonCorrelationSimilarity(dataModel);
		Recommender recommender = new GenericItemBasedRecommender(dataModel,
				similarity);
		List<RecommendedItem> recommendedItems = recommender.recommend(userId,
				howMany);
		return recommendedItems;
	}

	public List<RecommendedItem> userBasedCF(DataModel dataModel, long userId,
			int howMany) throws TasteException {
		UserSimilarity similarity = new PearsonCorrelationSimilarity(dataModel);
		UserNeighborhood neighborhood = new NearestNUserNeighborhood(NEARESTN,
				similarity, dataModel);
		Recommender recommender = new GenericUserBasedRecommender(dataModel,
				neighborhood, similarity);
		List<RecommendedItem> recommendedItems = recommender.recommend(userId,
				howMany);
		return recommendedItems;
	}

}
